using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using OfficeOpenXml;
using UnityEditor;
using UnityEngine;
using XFGameFramework.ExcelSystem;

namespace XFGameFramework.MissionSystem
{

    [CustomEditor(typeof(MissionsConfig))]
    public class MissionConfigInspector : Editor
    {

        private List<SerializedProperty> serializedProperties = null;

        private SerializedProperty m_Script = null;

        private void OnEnable()
        {
            serializedProperties = serializedObject.GetAllSerializedProperty();
            m_Script = serializedObject.FindProperty("m_Script");
        }


        public override void OnInspectorGUI()
        {
            serializedObject.Update();

            EditorGUI.BeginDisabledGroup(true);
            EditorGUILayout.PropertyField(m_Script);
            EditorGUI.EndDisabledGroup();

            foreach (var item in serializedProperties)
            { 
                if (item.name == "excel_path") continue;
                if (item.name == "start_id") continue;
                if (item.name == "type_script_guid") continue;

                EditorGUI.BeginDisabledGroup(item.name != "display_name");
                EditorGUILayout.PropertyField(item);
                EditorGUI.EndDisabledGroup();
            }

            OnGUIDataType();

            serializedObject.ApplyModifiedProperties();

            if (GUILayout.Button("编辑任务配表"))
            { 
                OpenMissionsConfig(target as MissionsConfig);
            }


            OnGUIExcel();

        }

        public static void OpenMissionsConfig(MissionsConfig missionsConfig) 
        {
            if (missionsConfig == null) return;

            ConfigsWindow window = EditorWindow.GetWindow<ConfigsWindow>();
            window.Show();
            window.SetCurrentConfigs(missionsConfig);
        }


        private GUIContent excel_path_content;

        private void OnGUIExcel()
        {
            MissionsConfig missionsConfig = target as MissionsConfig;
            if (missionsConfig == null)
                return;

            GUILayout.Space(10);

            if (!string.IsNullOrEmpty(missionsConfig.excel_path))
            {
                if (!File.Exists(missionsConfig.excel_path))
                {
                    missionsConfig.excel_path = string.Empty;
                    EditorUtility.SetDirty(missionsConfig);
                }

                EditorGUILayout.LabelField(string.Empty, "Excel路径", "BoldLabel");

                if (excel_path_content == null)
                    excel_path_content = new GUIContent();

                excel_path_content.text = missionsConfig.excel_path;
                excel_path_content.tooltip = missionsConfig.excel_path;

                EditorGUILayout.LabelField(excel_path_content);

                GUILayout.BeginHorizontal();

                GUILayout.FlexibleSpace();

                if (GUILayout.Button("更换Excel"))
                {
                    // 选择
                    string excel_path = EditorUtility.OpenFilePanel("请选择Excel文件", string.Format("{0}/../", Application.dataPath), "xlsx");
                    if (!string.IsNullOrEmpty(excel_path))
                    {
                        EditorApplication.delayCall += () =>
                        {
                            missionsConfig.excel_path = excel_path;
                            EditorUtility.SetDirty(missionsConfig);
                        };

                    }
                }
                if (GUILayout.Button("在文件夹中打开"))
                {
                    EditorApplication.delayCall += () =>
                    {
                        EditorUtility.RevealInFinder(missionsConfig.excel_path);
                    };
                }

                GUILayout.EndHorizontal();
            }

            GUILayout.BeginHorizontal();

            if (GUILayout.Button("导入Excel"))
            {
                EditorApplication.delayCall += () => ImportExcel(missionsConfig);
            }
            if (GUILayout.Button("导出Excel"))
            {
                EditorApplication.delayCall += () => ExportExcel(missionsConfig);
            }

            GUILayout.EndHorizontal();

        }


        private void ImportExcel(MissionsConfig missionsConfig)
        {
            if (string.IsNullOrEmpty(missionsConfig.excel_path))
            {
                // 选择
                string excel_path = EditorUtility.OpenFilePanel("请选择Excel文件", string.Format("{0}/../", Application.dataPath), "xlsx");
                if (string.IsNullOrEmpty(excel_path))
                    return;
                missionsConfig.excel_path = excel_path;
                EditorUtility.SetDirty(missionsConfig);
            }

            missionsConfig.display_name = GetDisplayName(Path.GetFileNameWithoutExtension(missionsConfig.excel_path));

            string guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(missionsConfig));
            string generate_path = string.Format("Assets/Extensions/MissionSystem/{0}", guid);

            ImportParams(missionsConfig);

            string error = null;
            if (ExcelManager.ExcelToScriptableObject(missionsConfig.excel_path, missionsConfig.missions, missionsConfig, out error, generate_path))
            {
                EditorWindow.focusedWindow.ShowNotification(new GUIContent("导入成功!"));
            }
            else
            {
                EditorWindow.focusedWindow.ShowNotification(new GUIContent(error));
            }

            foreach (var item in missionsConfig.missions)
            {
                item.parent = missionsConfig;
                EditorUtility.SetDirty(item);
            }

        }

        private void ImportParams(MissionsConfig missionsConfig)
        {
            using ExcelPackage package = new ExcelPackage(new FileInfo(missionsConfig.excel_path));

            ExcelWorksheet sheet = null;

            foreach (var item in package.Workbook.Worksheets)
            {
                if (item.Name == "params")
                {
                    sheet = item;
                    break;
                }
            }

            if (sheet == null)
            {
                sheet = package.Workbook.Worksheets.Add("params");
            }

            string e;
            ExcelManager.ExcelToList(sheet,missionsConfig.param, out e); 
        }


        private void ExportExcel(MissionsConfig missionsConfig)
        {
            if (string.IsNullOrEmpty(missionsConfig.excel_path))
            {
                // 选择
                string excel_path = EditorUtility.OpenFolderPanel("请选择Excel存放目录", string.Format("{0}/../../", Application.dataPath), string.Empty);
                if (string.IsNullOrEmpty(excel_path))
                    return;

                string fileName = missionsConfig.name;

                if (!string.IsNullOrEmpty(missionsConfig.display_name))
                    fileName = string.Format("{0}({1})", fileName, missionsConfig.display_name);

                missionsConfig.excel_path = string.Format("{0}/{1}.xlsx", excel_path, fileName);
                EditorUtility.SetDirty(missionsConfig);
            }

            ExportParams(missionsConfig);

            string error = null;
            if (ExcelManager.ScriptableObjectToExcel(missionsConfig.missions, missionsConfig.excel_path, out error))
            {
                EditorWindow.focusedWindow.ShowNotification(new GUIContent("导出成功!"));
            }
            else
            {
                EditorWindow.focusedWindow.ShowNotification(new GUIContent(error));
            }

        }


        private void ExportParams(MissionsConfig missionsConfig )
        {
            using ExcelPackage package = new ExcelPackage(new FileInfo(missionsConfig.excel_path));

            ExcelWorksheet sheet = null;

            foreach (var item in package.Workbook.Worksheets)
            {
                if (item.Name == "params")
                {
                    sheet = item;
                    break;
                }
            }

            if (sheet == null)
            {
                if (package.Workbook.Worksheets.Count == 0)
                    package.Workbook.Worksheets.Add("missions"); 
                sheet = package.Workbook.Worksheets.Add("params");
            }

            string e; 
            ExcelManager.ListToExcel(missionsConfig.param, sheet, out e);

            package.Save();
        }

        private string GetDisplayName(string name)
        {
            if (name.EndsWith(")") && name.Contains("("))
            {
                for (int i = name.Length - 1; i >= 0; i--)
                {
                    if (name[i] == '(')
                    {
                        return name.Substring(i + 1, name.Length - i - 2);
                    }
                }
            }

            return string.Empty;
        }

        #region 配置类型

        private GUIContent classTypeContent;

        private List<MonoScript> configDatas;

        private GUIStyle dropdown_style;

        private GUIStyle labelStyle;

        // 绘制数据类型
        private void OnGUIDataType()
        {
            MissionsConfig skillsConfig = target as MissionsConfig;

            if (skillsConfig == null) return;

            GUILayout.Space(10);

            Type type = null;

            if (!string.IsNullOrEmpty(skillsConfig.type_script_guid))
            {
                string asset_path = AssetDatabase.GUIDToAssetPath(skillsConfig.type_script_guid);
                MonoScript script = AssetDatabase.LoadAssetAtPath<MonoScript>(asset_path);
                Type t = script.GetClass();
                if (t.IsSubclassOf(typeof(MissionConfigData)) || t == typeof(MissionConfigData))
                    type = t;
            }

            string message = type == null ? "空" : GetDisplayName(type);

            if (classTypeContent == null)
                classTypeContent = new GUIContent(EditorGUIUtility.IconContent("d_cs Script Icon"));

            classTypeContent.text = message;

            GUILayout.BeginHorizontal();

            GUILayout.Label("数据类型");

            GUILayout.Space(50);

            if (dropdown_style == null)
            {
                dropdown_style = new GUIStyle("DropDown");
                dropdown_style.richText = true;
            }

            if (EditorGUILayout.DropdownButton(classTypeContent, FocusType.Passive, dropdown_style, GUILayout.MinWidth(0)))
            {
                List<MonoScript> scripts = GetAllConfigDatas();

                GenericMenu generic = new GenericMenu();

                generic.AddItem(new GUIContent("空"), false, () =>
                {
                    skillsConfig.type_script_guid = string.Empty;
                    EditorUtility.SetDirty(skillsConfig);
                    AssetDatabase.SaveAssets();
                });

                generic.AddSeparator(string.Empty);

                foreach (var item in scripts)
                {
                    GUIContent content = new GUIContent(EditorGUIUtility.IconContent("d_cs Script Icon"));
                    content.text = item.GetClass().Name;
                    if (!string.IsNullOrEmpty(item.GetClass().Namespace))
                        content.text = string.Format("{0}({1})", content.text, item.GetClass().Namespace);

                    string guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(item));

                    bool isOn = skillsConfig.type_script_guid == guid;

                    generic.AddItem(content, isOn, () =>
                    {
                        skillsConfig.type_script_guid = guid;
                        EditorUtility.SetDirty(skillsConfig);
                        AssetDatabase.SaveAssets();
                    });
                }

                generic.ShowAsContext();

            }

            GUILayout.EndHorizontal();


            if (labelStyle == null)
            {
                labelStyle = new GUIStyle("WordWrappedLabel");
                labelStyle.normal.textColor = Color.grey;
                labelStyle.fontSize = 11;
            }

            GUILayout.Label("说明:如果数据类型为空,则表示该配表中可以创建任意类型的数据。如果不为空,该配表则仅能创建您指定的类型及其子类型的数据!", labelStyle);


            GUILayout.BeginHorizontal();


            EditorGUI.BeginDisabledGroup(type == null);

            GUILayout.FlexibleSpace();

            if (GUILayout.Button("编辑", GUILayout.Width(50)))
            {
                OpenAsset(skillsConfig.type_script_guid);
            }

            if (GUILayout.Button("选中", GUILayout.Width(50)))
            {
                SelectAsset(skillsConfig.type_script_guid);
            }

            EditorGUI.EndDisabledGroup();

            GUILayout.EndHorizontal();

            GUILayout.Space(10);

        }

        private string GetDisplayName(Type type)
        {

            if (string.IsNullOrEmpty(type.Namespace))
                return type.Name;

            return string.Format("{0}<color=grey>({1})</color>", type.Name, type.Namespace);
        }

        private List<MonoScript> GetAllConfigDatas()
        {
            if (configDatas == null)
                configDatas = new List<MonoScript>();

            configDatas.Clear();

            string[] scripts = AssetDatabase.FindAssets("t:Script");

            foreach (var guid in scripts)
            {
                string path = AssetDatabase.GUIDToAssetPath(guid);
                MonoScript script = AssetDatabase.LoadAssetAtPath<MonoScript>(path);

                if (script == null) continue;

                Type type = script.GetClass();

                if (type == null) continue;

                if (type.IsSubclassOf(typeof(MissionConfigData)))
                {
                    configDatas.Add(script);
                }
            }

            return configDatas;
        }

        public static void OpenAsset(string guid)
        {
            if (string.IsNullOrEmpty(guid)) return;
            string asset_path = AssetDatabase.GUIDToAssetPath(guid);
            if (string.IsNullOrEmpty(asset_path)) return;
            AssetDatabase.OpenAsset(AssetDatabase.LoadAssetAtPath(asset_path, typeof(UnityEngine.Object)));
        }

        public static void SelectAsset(string guid)
        {
            if (string.IsNullOrEmpty(guid)) return;
            string asset_path = AssetDatabase.GUIDToAssetPath(guid);
            if (string.IsNullOrEmpty(asset_path)) return;

            UnityEngine.Object obj = AssetDatabase.LoadAssetAtPath(asset_path, typeof(UnityEngine.Object));
            Selection.activeObject = obj;
            EditorGUIUtility.PingObject(obj);
        }

        #endregion

    }
}

